import { defined, createTaskProcessorWorker } from '../Ces/Cesium'

import weModule from '../../ThirdParty/WeWasm/we.js'

let we

async function initWorker(parameters) {
  const wasmConfig = parameters.webAssemblyConfig

  if (defined(wasmConfig) && defined(wasmConfig.wasmBinary)) {
    we = await weModule(wasmConfig);
  } else {
    we = await weModule()
  }
  return true
}

async function createIsoSurface(parameters, transferableObjects) {
  const IsoSurface = we.IsoSurface

  const isoInstance1 = IsoSurface.createInstance()
  isoInstance1.verbose = parameters.verbose
  isoInstance1.scale = parameters.scale
  isoInstance1.offset = parameters.offset
  isoInstance1.bufferSize = parameters.bufferSize

  const image = {
    ...parameters.rectangle,
    source: parameters.source,
  }

  isoInstance1.setImage(image)

  const result = isoInstance1.getResult(parameters.isoValues, parameters.multiple, 0)
  const vertex = result.position
  result.position = null

  IsoSurface.releaseInstance(isoInstance1)

  transferableObjects.push(vertex.buffer)

  return vertex
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
async function createIsobands(parameters, transferableObjects) {
  const { width, height, arrayBufferView, breaks, gridBox, options } = parameters

  const coordConv = options?.coordConv ?? false

  const IsoBand = we.IsoBand
  const isobandInstance = IsoBand.createInstance()

  const bands = []
  for (let i = 1; i < breaks.length; i++) {
    const lowerBand = +breaks[i - 1] // make sure the breaks value is a number
    const upperBand = +breaks[i]
    bands.push([lowerBand, upperBand])
  }

  const features = isobandInstance.isoBands(arrayBufferView, width, height, bands, gridBox, options)

  if (coordConv) {
    const typeArray2Coords = (typeArray) => {
      const newCoords = []
      for (let i = 0; i < typeArray.length; i += 2) {
        newCoords.push([typeArray[i], typeArray[i + 1]])
      }
      return newCoords
    }

    features.forEach((f) => {
      const rings = f.geometry.coordinates
      const newCoords = []
      for (let j = 0; j < rings.length; j++) {
        newCoords[j] = []
        const ring = rings[j]
        if (ring instanceof Float64Array) {
          newCoords[j] = typeArray2Coords(ring)
        } else {
          for (let i = 0; i < ring.length; i++) {
            newCoords[j].push(typeArray2Coords(ring[i]))
          }
        }
      }
      f.geometry.coordinates = newCoords
    })
  }

  // console.log('working')

  IsoBand.releaseInstance(isobandInstance)

  return { type: 'FeatureCollection', features }
}

async function createIsoContour(parameters, transferableObjects) {
  const wasmConfig = parameters.webAssemblyConfig
  if (defined(wasmConfig)) {
    return initWorker(parameters, transferableObjects)
  }

  if (parameters.type === 'isobands') {
    return createIsobands(parameters, transferableObjects)
  }

  return createIsoSurface(parameters, transferableObjects)
}

export default createTaskProcessorWorker(createIsoContour)
